package org.peterbjornx.graphics.jogl;

import org.peterbjornx.graphics.jogl.vecmath.Vector3f;

import javax.media.opengl.GL;
import java.awt.*;

/**
 * Created by IntelliJ IDEA.
 * User: PeterbjornX
 * Date: Apr 11, 2009
 * Time: 8:34:23 PM
 * >
 */
public abstract class AbstractJOGLRenderer extends Canvas{
    public Point currentMousePoint;
    public Vector3d vLook;
    public Vector3d vRight;
    public Vector3d vUp;
    public Vector3d vEye;
    public Point lastMousePoint;
    public boolean emulateFPS;
    public boolean wireframe;
    public boolean textured;
    public boolean depthtest;

    public void displayAxes(GL gl) {
    gl.glDisable(GL.GL_TEXTURE_2D);
    gl.glDisable(GL.GL_LIGHTING);
    gl.glDisable(GL.GL_COLOR_MATERIAL);
    gl.glLineWidth(3.0f);

    // Display red colored X axis
    gl.glColor3d(1.0, 0.0, 0.0);
    gl.glBegin(gl.GL_LINES);
    gl.glVertex3d(0.0, 0.0, 0.0);
    gl.glVertex3d(1.0, 0.0, 0.0);
    gl.glEnd();

    // Display green colored Y axis
    gl.glColor3d(0.0, 1.0, 0.0);
    gl.glBegin(gl.GL_LINES);
    gl.glVertex3d(0.0, 0.0, 0.0);
    gl.glVertex3d(0.0, 1.0, 0.0);
    gl.glEnd();

    // Display blue colored Z axis
    gl.glColor3d(0.0, 0.0, 1.0);
    gl.glBegin(gl.GL_LINES);
    gl.glVertex3d(0.0, 0.0, 0.0);
    gl.glVertex3d(0.0, 0.0, 1.0);
    gl.glEnd();

    gl.glLineWidth(1.0f);
    gl.glColor3d(1.0, 1.0, 1.0);
  	}

    public void updateView(GL gl) {

    updateViewMatrix(gl);
  //          glu.gluLookAt( vEye.x,    vEye.y,    vEye.z,
  //                        vLook.x,   vLook.y,   vLook.z,
  //                          vUp.x,     vUp.y,     vUp.z);
  }
    /**
   * Builds a view matrix.
   *
   * The final view matrix will take the form of:
   * <pre>
   *  |   rx    ry    rz   -(r.e)  |
   *  |   ux    uy    uz   -(u.e)  |
   *  |  -lx   -ly   -lz    (l.e)  |
   *  |    0     0     0       1   |
   *
   * Where r = Right vector
   *       u = Up vector
   *       l = Look vector
   *       e = Eye position in world space
   *       . = Dot-Product operation
   * </pre>
   *
   */
  private void updateViewMatrix(GL gl) {
    double view[] = {1.0, 0.0, 0.0, 0.0,
      0.0, 1.0, 0.0, 0.0,
      0.0, 0.0, 1.0, 0.0,
      0.0, 0.0, 0.0, 1.0
    };
    vLook.normalize();

    Vector3d.cross(vRight, vLook, vUp);
    vRight.normalize();

    Vector3d.cross(vUp, vRight, vLook);
    vUp.normalize();

    view[0] = vRight.x;
    view[1] = vUp.x;
    view[2] = -vLook.x;
    view[3] = 0.0;

    view[4] = vRight.y;
    view[5] = vUp.y;
    view[6] = -vLook.y;
    view[7] = 0.0;

    view[8] = vRight.z;
    view[9] = vUp.z;
    view[10] = -vLook.z;
    view[11] = 0.0;

    view[12] = -Vector3d.dot(vRight, vEye);
    view[13] = -Vector3d.dot(vUp, vEye);
    view[14] = Vector3d.dot(vLook, vEye);
    view[15] = 1.0;

//    System.out.println("  vEye: " + vEye);
//    System.out.println(" vLook: " + vLook);
//    System.out.println("   vUp: " + vUp);
//    System.out.println("vRight: " + vRight);

    gl.glMultMatrixd(view, 0);
  }

  public double[] matRotate(double mat[], double angle, Vector3d axis) {
    double s = Math.sin(angle * Math.PI / 180.0);
    double c = Math.cos(angle * Math.PI / 180.0);

    axis.normalize();

    mat[0] = c + (1 - c) * axis.x;
    mat[1] = (1 - c) * axis.x * axis.y + s * axis.z;
    mat[2] = (1 - c) * axis.x * axis.z - s * axis.y;
    mat[3] = 0.0;

    mat[4] = (1 - c) * axis.y * axis.x - s * axis.z;
    mat[5] = c + (1 - c) * Math.pow(axis.y, 2);
    mat[6] = (1 - c) * axis.y * axis.z + s * axis.x;
    mat[7] = 0.0;

    mat[8] = (1 - c) * axis.z * axis.x + s * axis.y;
    mat[9] = (1 - c) * axis.z * axis.z - s * axis.x;
    mat[10] = c + (1 - c) * Math.pow(axis.z, 2);
    mat[11] = 0.0;

    mat[12] = 0.0;
    mat[13] = 0.0;
    mat[14] = 0.0;
    mat[15] = 1.0;

    return mat;
  }

  public Vector3d transformVector(double mat[], Vector3d vec) {
    double x = vec.x;
    double y = vec.y;
    double z = vec.z;

    vec.x = x * mat[0] +
            y * mat[4] +
            z * mat[8];

    vec.y = x * mat[1] +
            y * mat[5] +
            z * mat[9];

    vec.z = x * mat[2] +
            y * mat[6] +
            z * mat[10];

    return vec;
  }
   /**
   * Source: http://local.wasp.uwa.edu.au/~pbourke/geometry/rotate/
   * s
   * @param angle
   */
  public void rotateLookVector( double angle ) {

    double a = angle * Math.PI/180.0;
    Quat4f q1 = new Quat4f((float)vUp.x, (float)vUp.y, (float)vUp.z, 0.0f);
    Quat4f q2 = new Quat4f((float)(vLook.x * Math.sin(a/2.0)),
                           (float)(vLook.y * Math.sin(a/2.0)),
                           (float)(vLook.z * Math.sin(a/2.0)),
                           (float)(Math.cos(a/2)));
    Quat4f q3 = new Quat4f();
    q3 = Quat4f.mult(q2, Quat4f.mult(q1, Quat4f.conjugate(q2)));

//    System.out.println("--------------angle: " + a + " ---------------------");
//    System.out.println("   vUp: " + vUp);
//    System.out.println("    q3: " + q3);

    vUp.x = q3.x;
    vUp.y = q3. y;
    vUp.z = q3.z;
  }
}
